﻿// Decompiled with JetBrains decompiler
// Type: MCM.LightInject.GenericArgumentMapper
// Assembly: MCMv5, Version=5.10.2.0, Culture=neutral, PublicKeyToken=null
// MVID: 7AB326B9-B2B4-41C2-9177-68E944071101
// Assembly location: D:\steam\steamapps\workshop\content\261550\2859238197\bin\Win64_Shipping_Client\MCMv5.dll

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;

#nullable disable
namespace MCM.LightInject
{
  [ExcludeFromCodeCoverage]
  internal class GenericArgumentMapper : IGenericArgumentMapper
  {
    public GenericMappingResult Map(Type genericServiceType, Type openGenericImplementingType)
    {
      string[] array = ((IEnumerable<Type>) openGenericImplementingType.GetTypeInfo().GenericTypeParameters).Select<Type, string>((Func<Type, string>) (t => t.Name)).ToArray<string>();
      Dictionary<string, Type> map = GenericArgumentMapper.CreateMap(genericServiceType, openGenericImplementingType, array);
      return new GenericMappingResult(array, (IDictionary<string, Type>) map, genericServiceType, openGenericImplementingType);
    }

    public Type TryMakeGenericType(Type genericServiceType, Type openGenericImplementingType)
    {
      GenericMappingResult genericMappingResult = this.Map(genericServiceType, openGenericImplementingType);
      if (!genericMappingResult.IsValid)
        return (Type) null;
      try
      {
        return openGenericImplementingType.MakeGenericType(genericMappingResult.GetMappedArguments());
      }
      catch (Exception ex)
      {
        return (Type) null;
      }
    }

    private static Dictionary<string, Type> CreateMap(
      Type genericServiceType,
      Type openGenericImplementingType,
      string[] genericParameterNames)
    {
      Dictionary<string, Type> map = new Dictionary<string, Type>(genericParameterNames.Length);
      Type[] argumentsOrParameters1 = GenericArgumentMapper.GetGenericArgumentsOrParameters(genericServiceType);
      if (argumentsOrParameters1.Length == 0)
        return map;
      genericServiceType = genericServiceType.GetTypeInfo().GetGenericTypeDefinition();
      Type[] argumentsOrParameters2 = GenericArgumentMapper.GetGenericArgumentsOrParameters(GenericArgumentMapper.GetBaseTypeImplementingGenericTypeDefinition(openGenericImplementingType, genericServiceType));
      GenericArgumentMapper.MapGenericArguments(argumentsOrParameters1, argumentsOrParameters2, (IDictionary<string, Type>) map);
      return map;
    }

    private static Type[] GetGenericArgumentsOrParameters(Type type)
    {
      TypeInfo typeInfo = type.GetTypeInfo();
      return typeInfo.IsGenericTypeDefinition ? typeInfo.GenericTypeParameters : typeInfo.GenericTypeArguments;
    }

    private static void MapGenericArguments(
      Type[] serviceTypeGenericArguments,
      Type[] baseTypeGenericArguments,
      IDictionary<string, Type> map)
    {
      for (int index = 0; index < baseTypeGenericArguments.Length; ++index)
      {
        Type typeGenericArgument1 = baseTypeGenericArguments[index];
        Type typeGenericArgument2 = serviceTypeGenericArguments[index];
        if (typeGenericArgument1.GetTypeInfo().IsGenericParameter)
          map[typeGenericArgument1.Name] = typeGenericArgument2;
        else if (typeGenericArgument1.GetTypeInfo().IsGenericType)
        {
          if (typeGenericArgument2.GetTypeInfo().IsGenericType)
            GenericArgumentMapper.MapGenericArguments(typeGenericArgument2.GetTypeInfo().GenericTypeArguments, typeGenericArgument1.GetTypeInfo().GenericTypeArguments, map);
          else
            GenericArgumentMapper.MapGenericArguments(serviceTypeGenericArguments, typeGenericArgument1.GetTypeInfo().GenericTypeArguments, map);
        }
      }
    }

    private static Type GetBaseTypeImplementingGenericTypeDefinition(
      Type implementingType,
      Type genericTypeDefinition)
    {
      Type type1 = (Type) null;
      if (genericTypeDefinition.GetTypeInfo().IsInterface)
      {
        type1 = implementingType.GetTypeInfo().ImplementedInterfaces.FirstOrDefault<Type>((Func<Type, bool>) (i => i.GetTypeInfo().IsGenericType && i.GetTypeInfo().GetGenericTypeDefinition() == genericTypeDefinition));
      }
      else
      {
        Type type2 = implementingType;
        while (!GenericArgumentMapper.ImplementsOpenGenericTypeDefinition(genericTypeDefinition, type2) && type2 != typeof (object))
          type2 = type2.GetTypeInfo().BaseType;
        if (type2 != typeof (object))
          type1 = type2;
      }
      return !(type1 == (Type) null) ? type1 : throw new InvalidOperationException("The generic type definition " + genericTypeDefinition.FullName + " not implemented by implementing type " + implementingType.FullName);
    }

    private static bool ImplementsOpenGenericTypeDefinition(
      Type genericTypeDefinition,
      Type baseType)
    {
      return baseType.GetTypeInfo().IsGenericType && baseType.GetTypeInfo().GetGenericTypeDefinition() == genericTypeDefinition;
    }
  }
}
